home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / PARSER / KPARS_00 / FPARSER.PAS < prev    next >
Pascal/Delphi Source File  |  1993-09-02  |  39KB  |  1,307 lines

  1. {$D+}
  2. {$F+}
  3. {$L+}
  4. UNIT Fparser;
  5. {+H
  6. ---------------------------------------------------------------------------
  7.   Version     - 0.00
  8.  
  9.   File        - FPARSER.PAS
  10.  
  11.   Copyright   - None. Public Domain.
  12.  
  13.   Author      - Keith S. Brown (except where otherwise noted)
  14.                 Surface mail:              Email:(brown@smd4.jsc.nasa.gov)
  15.                   K.Brown
  16.                   Code:NASA/JSC/ES64
  17.                   Houston, TX 77058 (USA)  Voice:713-483-8952
  18.  
  19.   Purpose     - 1. Translate an infix expression to tokenized RPN.
  20.                 2. Execute a tokenized RPN expression.
  21.  
  22.   Language    - Borland International's Turbo Pascal V:4.x+ for MS-DOS
  23.  
  24.   Remarks     - Handles standard Pascal computational assignment expressions.
  25.                 With some differences, ie.:
  26.  
  27.               ■ as per Ada, numeric values may contain embedded underscores.
  28.  
  29.               ■ only the first 63 characters of an identifier are significant
  30.  
  31.               ■ the semi-colon terminating an expression is optional.
  32.  
  33.               ■ the extended unary functions "ArcCos", "ArcSin", "Log"
  34.                 (base 10), "Sign", "Step", "Tan" are available as well as
  35.                 the standard Pascal unary functions "Abs", "ArcTan", "Cos",
  36.                 "Exp", "Ln", "Round", "Sin", "Sqr", "Sqrt", "Trunc".
  37.  
  38.               ■ the extended binary operators "^" (as in x^3, cube of x) are
  39.                 available as well as the standard Pascal binary operators
  40.                 of "+", "-", "*", "/", "DIV", and "MOD".
  41.  
  42.               ■ the extended trinary functions:
  43.                 "Gate(x,cntr,wide:REAL):REAL;"     (rectangular pulse),
  44.                 "Gaus(x,cntr,variance:REAL):REAL;" (Gaussian pulse),
  45.                 "Sinc(x,cntr,wide:REAL):REAL;"     (Sin(πƒx)/(πƒx)) and
  46.                 "Tri(x,cntr,wide:REAL):REAL;"      (Triangular pulse)
  47.                 are available.
  48.  
  49.               ■ The constants "Pi" (3.1415...) and "e" (2.7182...) are predefined.
  50.  
  51.  
  52.               ■ the assignment of the result to a variable is optional.
  53.                 However, if no assignment is made, use EvaluatePostfix
  54.                 instead of ExecutePostfix.
  55.  
  56.   Requires    - Turbo Power Professional's TPSTRING unit --> basic string handling
  57.                 (requires proc/functs: DisposeString, LeftPad, Str2Real, StringFromHeap, StringToHeap)
  58.                 KSTRING.PAS --> extended string handling
  59.                 KMATH.PAS   --> math functions
  60.  
  61.    Example:
  62.       BEGIN
  63.         InitSymbolTable;
  64.  
  65.         DefineParameter('y',30.0);
  66.         DefineParameter('x',0);
  67.  
  68.         IF TranslateToPostfix('x := Sin(y*Pi/180);') THEN
  69.           IF ExecutePostFix THEN
  70.             WriteLn('Result = ',ViewParameter('x'));
  71.       END;
  72.  
  73.    Example:
  74.       VAR
  75.         x : REAL;
  76.       BEGIN
  77.         InitSymbolTable;
  78.  
  79.         DefineParameter('y',30.0);
  80.  
  81.         IF TranslateToPostfix('Sin(y*Pi/180);') THEN
  82.           IF EvaluatePostFix(x) THEN
  83.             WriteLn('Result = ',x);
  84.       END;
  85.  
  86.   Reference   - Data Structures & Program Design, Robert L. Kruse
  87.                 (Chptr 8: The Polish Notation) pp311-355
  88.  
  89.   Revised     - 1991.0618 (KSB) Converted from GF and made a unit.
  90.               - 1993.0901 (KSB) Updated documentation.
  91. ---------------------------------------------------------------------------}
  92. INTERFACE
  93.  
  94. {}PROCEDURE InitSymbolTable;
  95.     {Must be called first
  96.     }
  97. {}PROCEDURE DefineParameter(s:STRING; v:REAL);
  98.     {call as many times as needed to define & initialize variables
  99.     }
  100. {}FUNCTION  ViewParameter(s:STRING):REAL;
  101.     {call after EvaluatePostfix to examine results
  102.     }
  103. {}FUNCTION  TranslateToPostfix(s:STRING):BOOLEAN;
  104.     {"Compiles" expression for use by EvaluatePostfix
  105.     }
  106. {}FUNCTION  ExecutePostfix:BOOLEAN;
  107.     {"Executes" expression "compiled" by TranslateToPostfix
  108.     }
  109. {}FUNCTION  EvaluatePostfix(VAR x:REAL):BOOLEAN;
  110.     {"Executes" expression "compiled" by TranslateToPostfix when
  111.       the result is not assigned to a variable.
  112.     }
  113.  
  114.      {====================================================================}
  115.  
  116. IMPLEMENTATION
  117. USES
  118.   TPstring,
  119.   Kmath,    Kstring;
  120.  
  121. CONST
  122.   LastSymbol  = 4;
  123.  
  124.   FirstUnary  = LastSymbol+1;  { index of first unary operator }
  125.   LastUnary   = LastSymbol+17; { index of last  unary operator }
  126.  
  127.   FirstBinary = LastUnary+1;   { index of first binary operator }
  128.   LastBinary  = LastUnary+7;   { index of last  binary operator }
  129.  
  130.   FirstTrinary= LastBinary+1;  { index of first trinary operator }
  131.   LastTrinary = LastBinary+4;  { index of last  trinary operator }
  132.  
  133.   AssgnOperand= LastTrinary+1;
  134.  
  135.   FirstOperand= AssgnOperand+1;{ index of first operands }
  136.   LastOperand = AssgnOperand+2;{ index of last predefined operand; others introduced by the user with the expression }
  137.  
  138.   MaxExpression    = 255;      { maximum number of tokens in an expression }
  139.   MaxPriority = 7;             { largest priority of any operator }
  140.   MaxToken    = 100;
  141.   MaxStack    = 100;           { max stack size }
  142.  
  143.   NameLength  = 63;            { number of characters in an identifier }
  144.   HashSize    = 101;
  145.  
  146. TYPE
  147.   exprindex   = 0..MaxExpression;
  148.   indexstring = 0..255;
  149.   NAME   = STRING[NameLength];
  150.   priorrange  = 1..MaxPriority;
  151.   token  = 0..MaxToken;
  152.   value  = REAL;               { for simplicity, keep all the variables real }
  153.  
  154.   expPtr = ^expression;
  155.   expression  =
  156.   RECORD
  157.     L : exprIndex;
  158.     e : ARRAY[1..MaxExpression]OF token;
  159.   END {RECORD};
  160.  
  161.   tokenkind   = (
  162.   operand,
  163.   unaryop,
  164.   binaryop,
  165.   trinaryop,
  166.   assignOp,
  167.   endexpression,
  168.   leftparen,
  169.   rightparen,
  170.   comma);
  171.  
  172.   deftoken    =
  173.   RECORD
  174.     nm : POINTER;
  175.     CASE k : tokenkind OF
  176.       operand    : (Val : REAL);
  177.       unaryop,
  178.       binaryop,
  179.       trinaryop,
  180.       assignop   : (pri : priorrange);
  181.       endexpression,
  182.       leftparen,
  183.       rightparen,
  184.       comma      : ()
  185.   END {RECORD};
  186.  
  187.  
  188.  
  189. VAR
  190.   infix  : expression;     { tokenized infix expression }
  191.   postfix: expression;     { tokenized RPN expression   }
  192.  
  193. CONST
  194.   e_UnknownId = 1;
  195.   e_DataTooBig= 2;
  196.   e_IdExpected= 3;
  197.   e_BadConstPos    = 4;
  198.   e_BadRealConst   = 5;
  199.   e_UnknSymbol= 6;
  200.   e_CloseParen= 7;
  201.   e_BadBiOpPos= 8;
  202.   e_BiOpExpected   = 9;
  203.   e_UnequalParen   = 10;
  204.   e_BadExpression  = 11;
  205.   e_CodeOverflow   = 12;
  206.   e_BadGetVal = 13;
  207.   e_BadUniOpCode   = 14;
  208.   e_BadBiOpCode    = 15;
  209.   e_ZeroDivide= 16;
  210.   e_BadFloatOp= 17;
  211.   e_BadTriOpcode   = 18;
  212.  
  213.  
  214. {}FUNCTION ErrMsg(n:WORD):STRING;
  215. {---------------------------------------------------------------------------
  216.   Purpose     - Return a descriptive error message for an error number.
  217. ---------------------------------------------------------------------------}
  218.   CONST   {....^....1....^....2....^....3....^....4....^....5....^}
  219.     errs : ARRAY [1..18] OF STRING[37] = (
  220. {*}'Unknown identifier',
  221. {*}'Data segment too large',
  222. {*}'Identifier expected',
  223. {*}'Constant in illegal position',
  224. {*}'Error in Real Constant',
  225. {*}'Unrecognized symbol in expression',
  226. {*}'Illegal place for closing parenthesis',
  227. {*}'Binary operator in illegal position',
  228. {*}'Binary operator or ) expected',
  229. {*}'Unmatched parentheses',
  230. {*}'Error in expression',
  231.  
  232. {*}'Code overflow',
  233. {*}'Attempt to get value for non-operand',
  234. {*}'Unary operator code out of range',
  235. {*}'Binary operator code out of range',
  236. {*}'Division by zero',
  237. {*}'Invalid floating point operation',
  238. {*}'Trinary operator code out of range'
  239. );
  240.   BEGIN
  241.     ErrMsg := errs[n];
  242. {}END {ErrMsg};
  243.  
  244.  
  245.  
  246.  
  247. {}FUNCTION NumPars(s:STRING):REAL;
  248. {---------------------------------------------------------------------------
  249.   Purpose     - Convert a string to a real and default to zero if unparsable.
  250. ---------------------------------------------------------------------------}
  251.   VAR
  252.     r    : REAL;
  253.   BEGIN
  254.     IF NOT Str2Real(ReplaceAll(s,'_',''),r) THEN
  255.       r := 0;
  256.     NumPars := r;
  257. {}END {NumPars};
  258.  
  259.  
  260.  
  261.  
  262.                     {--------------------------------------}
  263.  
  264. TYPE
  265.   StackObj    = OBJECT
  266. {---------------------------------------------------------------------------
  267.   Purpose     - Stack manager for "compiling" and "executing". Tokens,
  268.                 (symbol table indexes) are pushed/popped/looked at as reqd.
  269. ---------------------------------------------------------------------------}
  270.     size    : 0..MaxStack;      { number of operators on stack }
  271.     stack   : ARRAY[1..MaxStack] OF token;
  272.  
  273.     CONSTRUCTOR Init;
  274.     PROCEDURE   Push(t:Token);
  275.     FUNCTION    Pop      :Token;
  276.     FUNCTION    LookAt(i:WORD):Token;
  277.     PROCEDURE   Error(n:WORD);
  278.   END {OBJECT};
  279.  
  280.  
  281.  
  282.  
  283. {}CONSTRUCTOR StackObj.Init;
  284.   BEGIN
  285.     FillChar(stack,SizeOf(stack),0);
  286.     size := 0;
  287. {}END {Init};
  288.  
  289.  
  290.  
  291.  
  292. {}PROCEDURE StackObj.Push(t : token);
  293.   BEGIN
  294.     IF size >= MaxStack THEN
  295.       Error(1)
  296.     ELSE BEGIN
  297.       Inc(size);
  298.       stack[size] := t;
  299.     END {IF};
  300. {}END {Push};
  301.  
  302.  
  303.  
  304.  
  305. {}FUNCTION StackObj.Pop:Token;
  306.   BEGIN
  307.     IF size <= 0 THEN
  308.       Error(2)
  309.     ELSE BEGIN
  310.       Pop := stack[size];
  311.       stack[size] := 0;
  312.       Dec(size);
  313.     END {IF};
  314. {}END {Pop};
  315.  
  316.  
  317.  
  318.  
  319. {}FUNCTION StackObj.LookAt(i:WORD):Token;
  320.   BEGIN
  321.     LookAt := stack[i];
  322. {}END {LookAt};
  323.  
  324.  
  325.  
  326.  
  327. {}PROCEDURE StackObj.Error(n:WORD);
  328.   CONST
  329.     errs : ARRAY[1..2]OF STRING[9]= ('overflow','underflow');
  330.   BEGIN
  331.     WriteLn('Stack Error: ',errs[n],'.');
  332.     Halt;
  333. {}END {Error};
  334.  
  335.  
  336.  
  337.  
  338.                     {--------------------------------------}
  339.  
  340. TYPE
  341.   SymbolTableObj   = OBJECT
  342. {---------------------------------------------------------------------------
  343.   Purpose     - Manages the Symbol table by adding identifiers/values,
  344.                 changing values for an id (or token), adding/deleting
  345.                 temporary variables, and returning type information for an
  346.                 existing symbol.
  347. ---------------------------------------------------------------------------}
  348.     size    : token;                        { number of distinct tokens }
  349.     entrys  : ARRAY[token]OF defToken;      { information on all tokens }
  350.  
  351.     CONSTRUCTOR Init;
  352.     PROCEDURE   AddOperand(n:NAME; v:REAL);
  353.     FUNCTION    GetValue(t:token):REAL;
  354.     PROCEDURE   SetValue(t:token; v:REAL);
  355.     FUNCTION    AddTemp(v:REAL):token;
  356.     PROCEDURE   RemoveTemps;
  357.     PROCEDURE   Error(n:WORD; INDEX:INTEGER; p:POINTER);
  358.     FUNCTION    Kind(t:token):tokenKind;
  359.     FUNCTION    KindType(t:token):STRING;
  360.   END {OBJECT};
  361.  
  362.  
  363.  
  364.  
  365. {}CONSTRUCTOR SymbolTableObj.Init;
  366.   BEGIN
  367.     size := 0;
  368.     FillChar(entrys,SizeOf(entrys),0);
  369. {}END {Init};
  370.  
  371.  
  372.  
  373.  
  374. {}FUNCTION SymbolTableObj.Kind(t : token) : tokenkind;
  375.   BEGIN
  376.     Kind := entrys[t].k;
  377. {}END {Kind};
  378.  
  379.  
  380.  
  381.  
  382. {}FUNCTION SymbolTableObj.KindType(t:token):STRING;
  383.   BEGIN
  384.     CASE entrys[t].k OF
  385.       operand      : KindType := 'Operand  ';
  386.       unaryop      : KindType := 'U Op code';
  387.       binaryop     : KindType := 'B Op code';
  388.       trinaryop    : KindType := 'T Op code';
  389.       endexpression: KindType := '-->END<--';
  390.       leftparen    : KindType := 'L paren  ';
  391.       rightparen   : KindType := 'R paren  ';
  392.       comma        : KindType := 'comma    ';
  393.     END {CASE};
  394. {}END {KindType};
  395.  
  396.  
  397.  
  398.  
  399. {}PROCEDURE SymbolTableObj.Error(n:WORD; INDEX:INTEGER; p:POINTER);
  400. {---------------------------------------------------------------------------
  401.   Remark      - N is the error number.
  402.                 P is either a pointer to an expression or to a string.
  403.             INDEX if negative, indicates that P points to a string. In such
  404.                   case ABS(INDEX) is the position in the string where the
  405.                   error occured.
  406.                   If positive, indicates that P points to an expression. In
  407.                   such a case the INDEX'th token is the one causing (or near
  408.                   to) the error.
  409. ---------------------------------------------------------------------------}
  410.   TYPE
  411.     StrPtr    = ^STRING;
  412.   VAR
  413.     s    : StrPtr ABSOLUTE p;
  414.     e    : ExpPtr ABSOLUTE p;
  415.   BEGIN
  416.     WriteLn('Symbol Table Error: (',n,') ',ErrMsg(n));
  417.  
  418.     IF p <> NIL THEN
  419.       IF INDEX < 0 THEN BEGIN
  420.         INDEX := Abs(INDEX);
  421.         WriteLn(s^);
  422.         WriteLn(LeftPad('^',INDEX));
  423.       END ELSE BEGIN
  424.       WriteLn('Error near ',StringFromHeap(entrys[e^.e[INDEX]].nm));
  425.     END {BEGIN};
  426.  
  427.     Halt;
  428. {}END {Error};
  429.  
  430.  
  431.  
  432.  
  433. {}PROCEDURE SymbolTableObj.AddOperand(n:NAME; v:REAL);
  434.   BEGIN
  435.     Inc(size);
  436.     WITH entrys[size] DO BEGIN
  437.       nm := StringToHeap(n);
  438.       k  := Operand;
  439.       Val:= v;
  440.     END {WITH};
  441. {}END {AddOperand};
  442.  
  443.  
  444.  
  445.  
  446. {}FUNCTION SymbolTableObj.GetValue(t : token) : REAL;
  447.   BEGIN
  448.     IF Kind(t) <> operand THEN
  449.       Error(e_BadGetVal,t,NIL)
  450.     ELSE
  451.       GetValue := entrys[t].Val;
  452. {}END {GetValue};
  453.  
  454.  
  455.  
  456.  
  457. {}PROCEDURE SymbolTableObj.SetValue(t:token; v:REAL);
  458.   BEGIN
  459.     WITH entrys[t] DO BEGIN
  460.       IF k <> operand THEN
  461.         Error(e_IdExpected,t,NIL)
  462.       ELSE
  463.         Val := v;
  464.     END {WITH};
  465. {}END {SetValue};
  466.  
  467.  
  468.  
  469.  
  470. {}FUNCTION  SymbolTableObj.AddTemp(v:REAL):token;
  471. {---------------------------------------------------------------------------
  472.   Remark      - All temporary variables are of the form "$T$nnn" where "nnn"
  473.                 is a unique integer value.
  474. ---------------------------------------------------------------------------}
  475.   BEGIN
  476.     Inc(size);
  477.     WITH entrys[size] DO BEGIN
  478.       nm := StringToHeap('$T$'+Long2Str(size));
  479.       k  := Operand;
  480.       Val:= v;
  481.     END {WITH};
  482.     AddTemp := size;
  483. {}END {AddTemp};
  484.  
  485.  
  486.  
  487.  
  488. {}PROCEDURE SymbolTableObj.RemoveTemps;
  489. {---------------------------------------------------------------------------
  490.   Remark      - Removes all temporary variables created during the execution
  491.                 of an RPN expression.
  492. ---------------------------------------------------------------------------}
  493.   BEGIN
  494.     WHILE size > FirstOperand DO
  495.       IF Copy(StringFromHeap(entrys[size].nm),1,3) = '$T$' THEN
  496.         WITH entrys[size] DO BEGIN
  497.           DisposeString(nm);
  498.           Val := 0;
  499.           Dec(size);
  500.         END {WITH} ELSE
  501.       Exit;
  502. {}END {RemoveTemps};
  503.  
  504.  
  505.  
  506.  
  507. VAR
  508.   dictionary  : SymbolTableObj;
  509.  
  510.                     {--------------------------------------}
  511.  
  512. TYPE
  513.   HashObj= OBJECT
  514. {---------------------------------------------------------------------------
  515.   Purpose     - Manages a hash table.
  516.   Remark      - The hash table is used to speed up the symbol table access,
  517.                 so that the entire table need not be searched to check for
  518.                 a symbol's existance.
  519. ---------------------------------------------------------------------------}
  520.     h  : ARRAY[0..HashSize]OF Token;
  521.  
  522.     CONSTRUCTOR Init;
  523.     FUNCTION    Hash(x:NAME):WORD;
  524.     FUNCTION    LookFor(x:NAME):Token;
  525.     PROCEDURE   AssignToken(x:NAME;t:Token);
  526.     PROCEDURE   Error;
  527.   END {OBJECT};
  528.  
  529.  
  530.  
  531.  
  532. {}PROCEDURE HashObj.Error;
  533.   BEGIN
  534.     WriteLn('Hash Error: Attempt to hash zero length string.');
  535.     Halt;
  536. {}END {Error};
  537.  
  538.  
  539.  
  540.  
  541. {}PROCEDURE HashObj.AssignToken(x:NAME;t:Token);
  542.   BEGIN
  543.     h[Hash(x)] := t;
  544. {}END {AssignToken};
  545.  
  546.  
  547.  
  548.  
  549. {}FUNCTION HashObj.LookFor(x:NAME):Token;
  550.   BEGIN
  551.     LookFor := h[Hash(x)];      { look for token in hash table }
  552. {}END {LookFor};
  553.  
  554.  
  555.  
  556.  
  557. {}FUNCTION HashObj.Hash(x : NAME) : WORD;
  558.   VAR
  559.     a    : INTEGER;
  560.     ch   : CHAR;
  561.     found: BOOLEAN;
  562.   BEGIN
  563.     IF Length(x) <= 0 THEN
  564.       Error
  565.     ELSE BEGIN
  566.       ch := x[1];
  567.       a  := Abs(Ord(ch)) MOD hashsize;
  568.       REPEAT
  569.         IF h[a] = 0 THEN
  570.           found := TRUE
  571.         ELSE
  572.         IF StringFromHeap(dictionary.entrys[h[a]].nm) = x THEN
  573.           found := TRUE
  574.         ELSE BEGIN
  575.           IF Length(x) > 1 THEN BEGIN
  576.             ch := x[2];
  577.             a  := a + Abs(Ord(ch))
  578.           END ELSE
  579.             a  := a + 29;
  580.  
  581.           IF a > hashsize THEN
  582.             a := a MOD hashsize;
  583.  
  584.           found := FALSE;
  585.         END {IF};
  586.       UNTIL found;
  587.       Hash := a;
  588.     END {IF};
  589. {}END {Hash};
  590.  
  591.  
  592.  
  593.  
  594. {}CONSTRUCTOR HashObj.Init;
  595.   VAR
  596.     t    : token;
  597.   BEGIN
  598.     FillChar(h,SizeOf(h),0);    { Initialize hash table }
  599.  
  600.     FOR t := 1 TO lastoperand DO
  601.       h[Hash(StringFromHeap(dictionary.entrys[t].nm))] := t;
  602. {}END {Init};
  603.  
  604.  
  605.  
  606.  
  607. VAR
  608.   h : HashObj;             {global because is used by DefineParameter,
  609.                                  ViewParameter and TranslateToPostfix}
  610.  
  611.                     {--------------------------------------}
  612.  
  613.  
  614. {}PROCEDURE InitSymbolTable;
  615. {+H
  616. ---------------------------------------------------------------------------
  617.   Purpose     - Initialize the defaults in the symbol table.
  618.  
  619.   Declaration - procedure InitSymbolTable.
  620.  
  621.   Remarks     - Must be called first to initialize symbols and operators.
  622. ---------------------------------------------------------------------------}
  623.   BEGIN
  624.     dictionary.Init;
  625.  
  626.     WITH dictionary DO BEGIN
  627.       WITH entrys[ 1] DO BEGIN nm := StringToHeap(';');     k := endexpression;      END {WITH};
  628.       WITH entrys[ 2] DO BEGIN nm := StringToHeap('(');     k := leftparen;          END {WITH};
  629.       WITH entrys[ 3] DO BEGIN nm := StringToHeap(')');     k := rightparen;         END {WITH};
  630.       WITH entrys[ 4] DO BEGIN nm := StringToHeap(',');     k := comma;              END {WITH};
  631.  
  632.   {01}WITH entrys[ 5] DO BEGIN nm := StringToHeap('~');     k := unaryop;  pri := 6; END {WITH};
  633.   {02}WITH entrys[ 6] DO BEGIN nm := StringToHeap('ABS');   k := unaryop;  pri := 7; END {WITH};
  634.   {03}WITH entrys[ 7] DO BEGIN nm := StringToHeap('SQR');   k := unaryop;  pri := 7; END {WITH};
  635.   {04}WITH entrys[ 8] DO BEGIN nm := StringToHeap('SQRT');  k := unaryop;  pri := 7; END {WITH};
  636.   {05}WITH entrys[ 9] DO BEGIN nm := StringToHeap('EXP');   k := unaryop;  pri := 7; END {WITH};
  637.   {06}WITH entrys[10] DO BEGIN nm := StringToHeap('LN');    k := unaryop;  pri := 7; END {WITH};
  638.   {07}WITH entrys[11] DO BEGIN nm := StringToHeap('LOG');   k := unaryop;  pri := 7; END {WITH};
  639.   {08}WITH entrys[12] DO BEGIN nm := StringToHeap('SIN');   k := unaryop;  pri := 7; END {WITH};
  640.   {09}WITH entrys[13] DO BEGIN nm := StringToHeap('COS');   k := unaryop;  pri := 7; END {WITH};
  641.   {10}WITH entrys[14] DO BEGIN nm := StringToHeap('TAN');   k := unaryop;  pri := 7; END {WITH};
  642.   {11}WITH entrys[15] DO BEGIN nm := StringToHeap('ARCSIN');k := unaryop;  pri := 7; END {WITH};
  643.   {12}WITH entrys[16] DO BEGIN nm := StringToHeap('ARCCOS');k := unaryop;  pri := 7; END {WITH};
  644.   {13}WITH entrys[17] DO BEGIN nm := StringToHeap('ARCTAN');k := unaryop;  pri := 7; END {WITH};
  645.   {14}WITH entrys[18] DO BEGIN nm := StringToHeap('ROUND'); k := unaryop;  pri := 7; END {WITH};
  646.   {15}WITH entrys[19] DO BEGIN nm := StringToHeap('TRUNC'); k := unaryop;  pri := 7; END {WITH};
  647.   {16}WITH entrys[20] DO BEGIN nm := StringToHeap('SIGN');  k := unaryop;  pri := 7; END {WITH};
  648.   {17}WITH entrys[21] DO BEGIN nm := StringToHeap('STEP');  k := unaryop;  pri := 7; END {WITH};
  649.  
  650.   {01}WITH entrys[22] DO BEGIN nm := StringToHeap('+');     k := binaryop; pri := 4; END {WITH};
  651.   {02}WITH entrys[23] DO BEGIN nm := StringToHeap('-');     k := binaryop; pri := 4; END {WITH};
  652.   {03}WITH entrys[24] DO BEGIN nm := StringToHeap('*');     k := binaryop; pri := 5; END {WITH};
  653.   {04}WITH entrys[25] DO BEGIN nm := StringToHeap('/');     k := binaryop; pri := 5; END {WITH};
  654.   {05}WITH entrys[26] DO BEGIN nm := StringToHeap('DIV');   k := binaryop; pri := 5; END {WITH};
  655.   {06}WITH entrys[27] DO BEGIN nm := StringToHeap('MOD');   k := binaryop; pri := 5; END {WITH};
  656.   {07}WITH entrys[28] DO BEGIN nm := StringToHeap('^');     k := binaryop; pri := 7; END {WITH};
  657.  
  658.   {01}WITH entrys[29] DO BEGIN nm := StringToHeap('GATE');  k := trinaryop;pri := 7; END {WITH};
  659.   {02}WITH entrys[30] DO BEGIN nm := StringToHeap('GAUS');  k := trinaryop;pri := 7; END {WITH};
  660.   {03}WITH entrys[31] DO BEGIN nm := StringToHeap('SINC');  k := trinaryop;pri := 7; END {WITH};
  661.   {04}WITH entrys[32] DO BEGIN nm := StringToHeap('TRI');   k := trinaryop;pri := 7; END {WITH};
  662.  
  663.   {01}WITH entrys[33] DO BEGIN nm := StringToHeap(':=');    k := assignop; pri := 1; END {WITH};
  664.  
  665.   {01}WITH entrys[34] DO BEGIN nm := StringToHeap('PI');    k := operand;  Val := Pi;END {WITH};
  666.   {02}WITH entrys[35] DO BEGIN nm := StringToHeap('E');     k := operand;  Val := Exp(1); END {WITH};
  667.     END {WITH};
  668.  
  669.     dictionary.size := lastoperand;
  670.     h.Init;
  671. {}END {InitSymbolTable};
  672.  
  673.  
  674.  
  675.  
  676. {}FUNCTION TranslateToPostfix(s:STRING):BOOLEAN;
  677. {+H
  678. ---------------------------------------------------------------------------
  679.   Purpose     - Translate an infix expression to RPN.
  680.  
  681.   Declaration - function TranslateToPostfix(s:STRING):BOOLEAN;
  682.  
  683.   Remarks     - The infix expression is first tokenized. However, all
  684.                 identifiers must be previously declared.
  685. ---------------------------------------------------------------------------}
  686.   CONST
  687.     maxstring = 255;            { maximum length of input string}
  688.   TYPE
  689.     indexname = 0..NameLength;  { used to loop through a name }
  690.     indexstring    = 0..maxstring;  { used to traverse input string }
  691.   VAR
  692.     position  : indexstring;    { moves through input string }
  693.     stx  : StackObj;
  694.  
  695.  
  696. {}{}FUNCTION  ReadExpression(s:STRING):BOOLEAN;
  697.     CONST
  698.       IsTri   : BOOLEAN = FALSE;
  699.       commas  : WORD    = 0;
  700.       digit   : SET OF CHAR  = ['0'..'9'];
  701.     VAR
  702.       parenCnt: INTEGER;        { checks for balanced parentheses }
  703.       term    : WORD;
  704.  
  705.  
  706. {}{}{}FUNCTION Leading : BOOLEAN;
  707.       VAR
  708.         k: tokenkind;
  709.       BEGIN
  710.         IF infix.L = 0 THEN
  711.           Leading := TRUE       { This is start of expression }
  712.         ELSE BEGIN
  713.           k := dictionary.Kind(infix.e[infix.L]); { Look at preceding token.}
  714.           Leading := (k = leftparen) OR
  715.                       (k = unaryop)   OR
  716.                       (k = binaryop)  OR
  717.                       (k = trinaryop) OR
  718.                       (k = assignop)  OR
  719.                       (k = comma);
  720.         END {IF};
  721. {}{}{}END {Leading};
  722.  
  723.  
  724. {}{}{}PROCEDURE PutToken(t : token);
  725.       BEGIN
  726.         Inc(infix.L);
  727.         infix.e[infix.L] := t;
  728. {}{}{}END {PutToken};
  729.  
  730.  
  731. {}{}{}PROCEDURE Find_word;
  732. {---------------------------------------------------------------------------
  733.   Purpose     - Extract an alpha-numeric symbol from the input text.
  734. ---------------------------------------------------------------------------}
  735.       CONST
  736.         alphabet   : SET OF CHAR  = ['A'..'Z','_'];
  737.       VAR
  738.         a_word: NAME;
  739.         t: token;
  740.         i: indexname;
  741.         newPos: indexstring;
  742.         ch    : CHAR;
  743.       BEGIN
  744.         newPos := Succ(position);     { find end of a_word }
  745.         WHILE s[newPos] IN (alphabet + digit) DO
  746.           Inc(newPos);
  747.  
  748.         IF newPos - position <= NameLength THEN
  749.           a_word := Copy(s,position,newPos - position)
  750.         ELSE                          { truncate to NameLength characters }
  751.           a_word := Copy(s,position,NameLength);
  752.  
  753.         t := h.LookFor(a_word);       { look for token in hash table }
  754.         IF t <> 0 THEN                { token is already defined }
  755.           IF Leading THEN
  756.             IF dictionary.Kind(t) = binaryop THEN
  757.               dictionary.Error(e_BadBiOpPos,-newPos,@s)
  758.             ELSE
  759.               PutToken(t)             { Other kinds are legal in leading position }
  760.           ELSE                        { not in a leading position }
  761.           IF dictionary.Kind(t) <> binaryop THEN
  762.             dictionary.Error(e_BiOpExpected,-newPos,@s)
  763.           ELSE
  764.             PutToken(t)
  765.         ELSE
  766.           dictionary.Error(e_UnknownId,-newPos,@s); { Unknown or undefined}
  767.  
  768.         position := newPos;
  769. {}{}{}END {Find_word};
  770.  
  771.  
  772. {}{}{}PROCEDURE FindNumber;
  773.       VAR
  774.         numbername,
  775.         x: STRING[80];
  776.         decpoint,               { position of decimal point, if any }
  777.         scinot,                 { position of start of scientific notation}
  778.         newPos: indexstring;
  779.         fraction,
  780.         r: REAL;                { value of number, converted to binary }
  781.         i: INTEGER;
  782.       BEGIN
  783.         IF NOT Leading THEN
  784.           dictionary.Error(e_BadConstPos,infix.L,@infix)
  785.         ELSE
  786.         IF dictionary.size >= maxtoken THEN
  787.           dictionary.Error(e_DataTooBig,infix.L,@infix)
  788.         ELSE BEGIN
  789.           newPos := position;   { Legal case; name a new token }
  790.  
  791.           WHILE s[newPos] IN digit+['_'] DO
  792.             Inc(newPos);
  793.  
  794.           x := Copy(s,position,newPos - position);
  795.  
  796.           IF s[newPos] = '.' THEN BEGIN
  797.             decpoint := newPos; { fractional part }
  798.             REPEAT
  799.               Inc(newPos)
  800.             UNTIL  NOT (s[newPos] IN digit+['_']);
  801.             x := x + Copy(s,decpoint,newPos - decpoint);
  802.           END {IF};
  803.  
  804.           IF s[newPos] IN ['E','e'] THEN BEGIN
  805.             scinot := newPos;
  806.             Inc(newPos);
  807.             IF  NOT (s[newPos] IN ['+','-'] + digit) THEN
  808.               dictionary.Error(e_BadRealConst,newPos,@s);
  809.             REPEAT
  810.               Inc(newPos);
  811.             UNTIL  NOT (s[newPos] IN digit+['_']);
  812.             x := x + Copy(s,scinot,newPos - scinot);
  813.           END {IF};
  814.  
  815.           r := NumPars(x);
  816.           Inc(dictionary.size);
  817.           WITH dictionary.entrys[dictionary.size] DO BEGIN
  818.             Str(r,numberName);  { normalized string rep }
  819.             nm := StringToHeap(numberName);
  820.             k  := operand;
  821.             Val:= r;
  822.           END {WITH};
  823.  
  824.           PutToken(dictionary.size);
  825.           position := newPos;
  826.         END {IF};
  827. {}{}{}END {FindNumber};
  828.  
  829.  
  830. {}{}{}PROCEDURE FindSymbol;
  831. {}{}{}{}FUNCTION Next(s:STRING; n:indexString):CHAR;
  832.         VAR
  833.           L   : BYTE ABSOLUTE s;
  834.         BEGIN
  835.           IF n > L THEN
  836.             Next := ' '
  837.           ELSE
  838.             Next := s[n+1];
  839. {}{}{}{}END {Next};
  840.  
  841.  
  842. {}{}{}{}FUNCTION SySet(s:STRING; VAR n:indexString; i:BYTE):NAME;
  843.         BEGIN
  844.           SySet := s;
  845.           n := n + i;
  846. {}{}{}{}END {SySet};
  847.  
  848.  
  849.       CONST
  850.         symbols    : SET OF CHAR  = ['(',')','*','+',',','-','/',':','<','=','>'];
  851.       VAR
  852.         x: NAME;
  853.         L: BYTE ABSOLUTE s;
  854.         t: token;
  855.         newPos: indexString;
  856.       BEGIN
  857.         newPos := position;
  858.         x      := '';
  859.  
  860.         CASE s[newPos] OF
  861.           ':' :
  862.           CASE Next(s,newPos) OF
  863.             '=' : x := SySet(':=',newPos,+1);
  864.             ELSE
  865.               x := SySet(':', newPos, 0);
  866.           END {CASE};
  867.  
  868.           '<' :
  869.           CASE Next(s,newPos) OF
  870.             '>' : x := SySet('<>',newPos,+1);
  871.             '=' : x := SySet('<=',newPos,+1);
  872.             ELSE
  873.               x := SySet('<', newPos, 0);
  874.           END {CASE};
  875.  
  876.           '>' :
  877.           CASE Next(s,newPos) OF
  878.             '=' : x := SySet('>=',newPos,+1);
  879.             ELSE
  880.               x := SySet('>', newPos, 0);
  881.           END {CASE};
  882.  
  883.           ELSE
  884.             x := s[newPos];
  885.         END {CASE};
  886.  
  887.         t := h.LookFor(x);
  888.  
  889.         IF t = 0 THEN
  890.           dictionary.Error(e_UnknSymbol,-position,@s)
  891.         ELSE
  892.         IF Leading THEN
  893.           IF dictionary.Kind(t) = rightparen THEN
  894.             dictionary.Error(e_CloseParen,-position,@s)
  895.           ELSE
  896.           IF dictionary.Kind(t) = binaryop THEN BEGIN
  897.             CASE x [ 1 ] OF     { A binary operator is illegal here; it must be a unary operator}
  898.               '+' : ;
  899.               '-' :
  900.               BEGIN
  901.                 x := '~';       { unary negation }
  902.                 t := h.LookFor(x);
  903.                 PutToken(t);
  904.               END {BEGIN};
  905.  
  906.               ELSE
  907.                 dictionary.Error(e_BadBiOpPos,-position,@s);
  908.             END {CASE};
  909.           END ELSE
  910.             PutToken(t)         { other kinds are legal }
  911.       ELSE
  912.       IF (dictionary.Kind(t) = rightparen) OR   { not in leading position }
  913.             (dictionary.Kind(t) = comma)      OR
  914.             (dictionary.Kind(t) = binaryop)   OR
  915.             (dictionary.Kind(t) = assignOp) THEN
  916.         PutToken(t)
  917.       ELSE
  918.         dictionary.Error(e_BiOpExpected,-position,@s);
  919.  
  920.         IF dictionary.Kind(t) = leftparen THEN
  921.           Inc(parenCnt)
  922.         ELSE
  923.         IF dictionary.Kind(t) = rightparen THEN BEGIN
  924.           Dec(parenCnt);
  925.           IF parenCnt < 0 THEN
  926.             dictionary.Error(e_UnequalParen,-position,@s);
  927.         END {IF};
  928.  
  929.         position := newPos;
  930.         Inc(position);
  931. {}{}{}END {FindSymbol};
  932.  
  933.  
  934.     BEGIN  {--- ReadExpression ---}
  935.       s          := StUpCase(s) + ' '; { blank is a sentinel for searches }
  936.       infix.L    := 0;
  937.       parenCnt   := 0;
  938.       position   := 1;
  939.  
  940.       WHILE (position <= Length(s)) AND (s[position] <> ';') DO
  941.         CASE s[position] OF
  942.           ' '      : Inc(position); { skip all blanks between tokens }
  943.           'A'..'Z' : Find_word;
  944.           '0'..'9',
  945.           '.'      : FindNumber;
  946.           ELSE
  947.             FindSymbol;
  948.         END {CASE} ;
  949.  
  950.       IF parenCnt <> 0 THEN
  951.         dictionary.Error(e_UnequalParen,-position,@s);
  952.  
  953.       IF Leading THEN
  954.         dictionary.Error(e_BadExpression,infix.L,NIL);
  955.  
  956.       PutToken(1);              { Put endexpression into the output.}
  957. {}{}END {ReadExpression};
  958.  
  959.  
  960. {}{}PROCEDURE Translate;
  961.     VAR
  962.       t,                        { token currently being processed }
  963.       x  : token;               { operator popped from stack }
  964.       endright: BOOLEAN;
  965.  
  966. {}{}{}PROCEDURE GetToken(VAR t : token);
  967.       BEGIN
  968.         t := infix.e[infix.L];
  969.         Inc(infix.L);
  970.         IF infix.L > MaxExpression THEN
  971.           dictionary.Error(e_CodeOverflow,0,NIL);
  972. {}{}{}END {GetToken};
  973.  
  974.  
  975. {}{}{}PROCEDURE PutToken(t : token);
  976.       BEGIN
  977.         Inc(postfix.L);
  978.         postfix.e[postfix.L] := t;
  979. {}{}{}END {PutToken};
  980.  
  981.  
  982. {}{}{}FUNCTION Priority(t : token) : INTEGER;
  983.       BEGIN
  984.         Priority := dictionary.entrys[t].pri;
  985. {}{}{}END {Priority};
  986.  
  987.  
  988.     BEGIN
  989.       stx.Init;
  990.       infix.L := 1;
  991.       postfix.L := 0;
  992.       REPEAT
  993.         GetToken(t);
  994.         CASE dictionary.Kind ( t ) OF
  995.           operand    : PutToken(t);
  996.           leftparen  : stx.Push(t);
  997.           rightparen :
  998.           BEGIN
  999.             t := stx.Pop;
  1000.             WHILE dictionary.Kind(t) <> leftparen DO BEGIN
  1001.               PutToken(t);
  1002.               t := stx.Pop;     { discard left parenthesis }
  1003.             END {WHILE};
  1004.           END {BEGIN};
  1005.           unaryop,
  1006.           binaryop,
  1007.           trinaryop,
  1008.           assignop   :
  1009.           BEGIN
  1010.             REPEAT
  1011.               IF (stx.size = 0) OR
  1012.                  (dictionary.Kind(stx.LookAt(stx.size)) = leftparen) OR
  1013.                  (Priority(stx.LookAt(stx.size)) < Priority(t)) THEN
  1014.                 endright := TRUE
  1015.               ELSE BEGIN
  1016.                 endright := FALSE;
  1017.                 x := stx.Pop;
  1018.                 PutToken(x);
  1019.               END {IF};
  1020.             UNTIL endright;
  1021.             stx.Push(t);
  1022.           END {BEGIN};
  1023.  
  1024.           endexpression:
  1025.           WHILE stx.size > 0 DO
  1026.             PutToken(stx.Pop);  {empty the stack}
  1027.  
  1028.         END {CASE};
  1029.  
  1030.       UNTIL dictionary.Kind(t) = endexpression;
  1031.       PutToken(t);
  1032. {}{}END {Translate};
  1033.  
  1034.  
  1035.   BEGIN
  1036.     FillChar(infix,  SizeOf(expression),0);
  1037.     FillChar(postfix,SizeOf(expression),0);
  1038.  
  1039.     IF ReadExpression(s) THEN BEGIN
  1040.       Translate;
  1041.       TranslateToPostfix := TRUE;
  1042.     END ELSE
  1043.       TranslateToPostfix := FALSE;
  1044. {}END {TranslateToPostfix};
  1045.  
  1046.  
  1047.  
  1048.  
  1049. {}PROCEDURE DefineParameter(s:STRING; v:REAL);
  1050. {+H
  1051. ---------------------------------------------------------------------------
  1052.   Purpose     - If S is not defined add it with its value V to the symbol
  1053.                 table. If it is found, change its value to V.
  1054.  
  1055.   Declaration - procedure DefineParameter(s:STRING; v:REAL);
  1056. ---------------------------------------------------------------------------}
  1057.   VAR
  1058.     t    : Token;
  1059.   BEGIN
  1060.     s := StUpCase(Trim(s));
  1061.     t := h.LookFor(s);
  1062.  
  1063.     IF t <> 0 THEN BEGIN        { token is one already defined }
  1064.       IF t < FirstOperand THEN
  1065.         dictionary.Error(e_IdExpected,infix.L,NIL)
  1066.       ELSE
  1067.         dictionary.entrys[t].Val := v;
  1068.     END ELSE                    { new name for token; must set up definition }
  1069.     IF dictionary.size >= maxtoken THEN
  1070.       dictionary.Error(e_DataTooBig,infix.L,NIL)
  1071.     ELSE BEGIN
  1072.       Inc(dictionary.size);
  1073.       h.AssignToken(s,dictionary.size);
  1074.       WITH dictionary.entrys[dictionary.size] DO BEGIN
  1075.         nm := StringToHeap(s);
  1076.         k  := operand;
  1077.         Val:= v;
  1078.       END {WITH};
  1079.     END {IF};
  1080. {}END {DefineParameter};
  1081.  
  1082.  
  1083.  
  1084.  
  1085. {}FUNCTION  ViewParameter(s:STRING):REAL;
  1086. {+H
  1087. ---------------------------------------------------------------------------
  1088.   Purpose     - If S is not defined display an error message.  If it is
  1089.                 found, return its value.
  1090.  
  1091.   Declaration - function ViewParameter(s:STRING):REAL;
  1092. ---------------------------------------------------------------------------}
  1093.   VAR
  1094.     t    : Token;
  1095.   BEGIN
  1096.     s := StUpCase(Trim(s));
  1097.     t := h.LookFor(s);
  1098.  
  1099.     IF t <> 0 THEN BEGIN        { token is one already defined }
  1100.       IF t < FirstOperand THEN
  1101.         dictionary.Error(e_IdExpected,infix.L,NIL)
  1102.       ELSE
  1103.         ViewParameter := dictionary.entrys[t].Val;
  1104.     END ELSE
  1105.       dictionary.Error(e_IdExpected,0,NIL);
  1106. {}END {ViewParameter};
  1107.  
  1108.  
  1109.  
  1110.  
  1111. VAR
  1112.   RPNresult   : REAL;
  1113.  
  1114.  
  1115. {}FUNCTION  ExecutePostfix:BOOLEAN;
  1116. {+H
  1117. ---------------------------------------------------------------------------
  1118.   Purpose     - Interpret a RPN expression.
  1119.  
  1120.   Declaration - function ExecutePostfix:BOOLEAN;
  1121. ---------------------------------------------------------------------------}
  1122. {}{}PROCEDURE GetToken(VAR t : token);
  1123.     BEGIN
  1124.       t := postfix.e[postfix.L];
  1125.       Inc(postfix.L);
  1126.       IF postfix.L > MaxExpression THEN
  1127.         dictionary.Error(e_CodeOverflow,postfix.L,@postfix);
  1128. {}{}END {GetToken};
  1129.  
  1130.  
  1131. {}{}FUNCTION DoUnary(t : token;  x : REAL) : REAL;
  1132.     BEGIN
  1133.       IF (t < firstunary) OR
  1134.           (t > lastunary) THEN
  1135.         dictionary.Error(e_BadUniOpcode,postfix.L,@postfix)
  1136.       ELSE
  1137.         CASE (t-LastSymbol) OF
  1138.           1 : DoUnary :=  - x;
  1139.           2 : DoUnary := Abs(x);
  1140.           3 : DoUnary := Sqr(x);
  1141.  
  1142.           4 :
  1143.           IF x < 0 THEN
  1144.             dictionary.Error(e_BadFloatOp,postfix.L,@postfix)
  1145.           ELSE
  1146.             DoUnary := Sqrt(x);
  1147.  
  1148.           5 :
  1149.           IF x > 87 THEN
  1150.             DoUnary := Exp(87)
  1151.           ELSE
  1152.           IF x <  - 87 THEN
  1153.             DoUnary := 0
  1154.           ELSE
  1155.             DoUnary := Exp(x);
  1156.  
  1157.           6 :
  1158.           IF x <= 0 THEN
  1159.             dictionary.Error(e_BadFloatOp,postfix.L,@postfix)
  1160.           ELSE
  1161.             DoUnary := Ln(x);
  1162.  
  1163.           7 :
  1164.           IF x <= 0 THEN
  1165.             dictionary.Error(e_BadFloatOp,postfix.L,@postfix)
  1166.           ELSE
  1167.             DoUnary := Ln(x)/Ln(10);
  1168.  
  1169.           8 : DoUnary := Sin(x);
  1170.           9 : DoUnary := Cos(x);
  1171.           10 : DoUnary := Tan(x);
  1172.           11 : DoUnary := ArcSin(x);
  1173.           12 : DoUnary := ArcCos(x);
  1174.           13 : DoUnary := ArcTan(x);
  1175.           14 : DoUnary := Round(x);
  1176.           15 : DoUnary := Trunc(x);
  1177.           16 : DoUnary := Sign(x);
  1178.           17 : DoUnary := Step(x);
  1179.         END {CASE};
  1180. {}{}END {DoUnary};
  1181.  
  1182.  
  1183. {}{}FUNCTION DoBinary(t : token;  y,x : REAL) : REAL;
  1184.     VAR
  1185.       err: BYTE;
  1186.     BEGIN
  1187.       IF (t < firstbinary) OR
  1188.           (t > lastbinary) THEN
  1189.         dictionary.Error(e_BadBiOpCode,postfix.L,@postfix)
  1190.       ELSE
  1191.         CASE (t-LastUnary) OF
  1192.           1 : DoBinary := x + y;
  1193.           2 : DoBinary := x - y;
  1194.           3 : DoBinary := x*y;
  1195.  
  1196.           4 :
  1197.           IF y = 0 THEN
  1198.             dictionary.Error(e_ZeroDivide,postfix.L,@postfix)
  1199.           ELSE
  1200.             DoBinary := x/y;
  1201.  
  1202.           5 :
  1203.           IF Round(y) = 0 THEN
  1204.             dictionary.Error(e_ZeroDivide,postfix.L,@postfix)
  1205.           ELSE
  1206.             DoBinary := Round(x) DIV Round(y);
  1207.  
  1208.           6 :
  1209.           IF Round(y) = 0 THEN
  1210.             dictionary.Error(e_ZeroDivide,postfix.L,@postfix)
  1211.           ELSE
  1212.             DoBinary := Round(x) MOD Round(y);
  1213.  
  1214.           7 :
  1215.           BEGIN
  1216.             DoBinary := Exponent(x,y,err);
  1217.             IF err <> 0 THEN
  1218.               dictionary.Error(e_BadFloatOp,postfix.L,@postfix);
  1219.           END {BEGIN};
  1220.  
  1221.           8 :
  1222.           BEGIN
  1223.             x := y;
  1224.             DoBinary := x;
  1225.           END {BEGIN};
  1226.         END {CASE};
  1227. {}{}END {DoBinary};
  1228.  
  1229.  
  1230. {}{}FUNCTION DoTrinary(t:token; z,y,x:REAL) :REAL;
  1231.     BEGIN
  1232.       IF (t < firsttrinary) OR
  1233.           (t > lasttrinary) THEN
  1234.         dictionary.Error(e_BadTriOpcode,postfix.L,@postfix)
  1235.       ELSE
  1236.         CASE (t-LastBinary) OF
  1237.           1 : DoTrinary := Gate(x,y,z);
  1238.           2 : DoTrinary := Gaussian(x,y,z);
  1239.           3 : DoTrinary := Sinc(x,y,z);
  1240.           4 : DoTrinary := Triangle(x,y,z);
  1241.         END {CASE};
  1242. {}{}END {DoTrinary};
  1243.  
  1244.  
  1245.   VAR
  1246.     stx  : StackObj;
  1247.     t    : token;
  1248.   BEGIN {--- ExecutePostFix ---}
  1249.     ExecutePostFix := FALSE;
  1250.     stx.Init;
  1251.  
  1252.     postfix.L := 1;
  1253.     REPEAT
  1254.       GetToken(t);
  1255.       CASE dictionary.Kind(t) OF
  1256.         operand   : stx.Push(t);
  1257.  
  1258.         unaryOp   : stx.Push(dictionary.AddTemp(DoUnary(t,dictionary.GetValue(stx.Pop))));
  1259.  
  1260.         binaryOp  : stx.Push(dictionary.AddTemp(DoBinary(t,dictionary.GetValue(stx.Pop),dictionary.GetValue(stx.Pop))));
  1261.  
  1262.         trinaryOp : stx.Push(dictionary.AddTemp(DoTrinary(t,dictionary.GetValue(stx.Pop),
  1263.           dictionary.GetValue(stx.Pop),dictionary.GetValue(stx.Pop))));
  1264.  
  1265.         assignOp  :
  1266.         BEGIN
  1267.           t := stx.Pop;
  1268.           RPNresult := dictionary.GetValue(t);   { for possible Eval call}
  1269.           dictionary.SetValue(stx.Pop,dictionary.GetValue(t));
  1270.           dictionary.RemoveTemps;
  1271.         END {BEGIN};
  1272.       END {CASE};
  1273.     UNTIL dictionary.Kind(t) = EndExpression;
  1274.  
  1275.     IF stx.size = 1 THEN
  1276.       RPNresult := dictionary.GetValue(stx.Pop);
  1277.  
  1278.     ExecutePostFix := TRUE;
  1279. {}END {ExecutePostfix};
  1280.  
  1281.  
  1282.  
  1283.  
  1284. {}FUNCTION EvaluatePostfix(VAR x:REAL):BOOLEAN;
  1285. {+H
  1286. ---------------------------------------------------------------------------
  1287.   Purpose     - Interpret a RPN expression when the result is not assigned
  1288.                 to a variable.
  1289.  
  1290.   Declaration - function EvaluatePostfix(VAR x:REAL):BOOLEAN;
  1291. ---------------------------------------------------------------------------}
  1292.   BEGIN
  1293.     IF ExecutePostfix THEN BEGIN
  1294.       x := RPNresult;
  1295.       EvaluatePostfix := TRUE;
  1296.     END ELSE BEGIN
  1297.       x := 0;
  1298.       EvaluatePostfix := FALSE;
  1299.     END {BEGIN};
  1300. {}END {EvaluatePostfix};
  1301.  
  1302.  
  1303.  
  1304.  
  1305. BEGIN
  1306. END {BEGIN}.
  1307.